const _ = require("underscore");
const moment = require("moment/moment");
const decimal = require("decimal");

const util = {
   timeRangeObj:{
      "1":"sharp",
      "2":"peak",
      "3":"flat",
      "4":"valley",
   },
   deviceTypeObj:{
      "1":{
         name:"water",
         measureList:[1],
      },
      "2":{
         name:"electric",
         measureList:[2],
      },
      "3":{
         name:"cooling_tower",
         measureList:[],
      },
      "4":{
         name:"heat",
         measureList:[3,5],
      },
      "5":{
         name:"flow_meter",
         measureList:[5],
      },
      "6":{
         name:"heating_cooling_meter",
         measureList:[3,4,5],
      },
      "7":{
         name:"valve",
         measureList:[6],
      },
      "8":{
         name:"water_pump",
         measureList:[6],
      },
      "9":{
         name:"temperature",
         measureList:[],
      },
      "10":{
         name:"vav_temperature",
         measureList:[],
      },
      "11":{
         name:"sampling",
         measureList:[],
      },
      "12":{
         name:"refrigerating_machine",
         measureList:[6],
      },
   },
   organizeCostPlan:function (devicePlanList){
      let deviceObj = {
         deviceNo:devicePlanList[0].deviceNo,
         rangeList:[],
         lostPrice:0,
         costPlanType:devicePlanList[0].costPlanType,
      }
      devicePlanList = _.sortBy(devicePlanList,function (data){return moment(data.startRange).valueOf()});
      for(const column of devicePlanList){
         if(!column.startRange && !column.endRange){
            deviceObj.lostPrice = column.price;
         }else{
            deviceObj.rangeList.push({
               startRange:util.timeToNumber(column.startRange),
               endRange:util.timeToNumber(column.endRange),
               price:column.price,
               type:column.type
            })
         }
      }
      return deviceObj;
   },
   dailyCostCalculate:function (costPlan,deviceDataList){
      let costCalculateObj;
      if(costPlan.costPlanType === 2){
         costCalculateObj = util.timeRangeCalculate(costPlan,deviceDataList);
      }else if(costPlan.costPlanType === 3){
         let ladderBase = deviceDataList[0].ladderBase;
         let consumption = decimal.sub(deviceDataList[deviceDataList.length - 1].accumulate,deviceDataList[0].accumulate).internal;
         let ladderCalculateObj = util.ladderCalculate(costPlan,ladderBase,consumption);
         costCalculateObj = {
            date_accumulated:deviceDataList[deviceDataList.length - 1].accumulate,
            last_data_time:deviceDataList[deviceDataList.length - 1].endRange,
            date_consumption:consumption,
            date_cost_amount:ladderCalculateObj.amount,
            other_consumption:ladderCalculateObj.lostConsumption,
            other_cost_amount:ladderCalculateObj.lostAmount,
            cycle_consumption:ladderCalculateObj.newLadderBase
         }
      }else{
         let consumption = parseFloat(decimal.sub(deviceDataList[deviceDataList.length - 1].accumulate,deviceDataList[0].accumulate).internal);
         let amount = parseFloat(decimal.mul(consumption,costPlan.lostPrice).internal);
         costCalculateObj = {
            last_data_time:deviceDataList[deviceDataList.length - 1].endRange,
            date_accumulated:deviceDataList[deviceDataList.length - 1].accumulate,
            date_consumption:consumption,
            date_cost_amount:amount,
         }
      }
      return costCalculateObj;
   },
   timeToNumber:function (time){
      let timeSpiltList = time.split(":");
      return decimal.add(decimal.mul(parseInt(timeSpiltList[0]),3600).internal,decimal.mul(parseInt(timeSpiltList[1]), 60).internal,parseInt(timeSpiltList[2])).internal;
   },
   ladderCalculate(costPlan,ladderBase,consumption) {
      let newLadderBase = decimal.add(ladderBase,consumption).internal
      let amount = 0;
      let lostConsumption = 0;
      let lostAmount = 0;
      let startIndex = null;
      for(const range of costPlan.costPlanList){
         if(range.startRange >= parseInt(ladderBase)){
            let costStartRange = costPlan[costPlan.indexOf(range)-1];
            let rangeUsed = decimal.sub(costStartRange.endRange,ladderBase).internal
            amount = decimal.add(amount,decimal.mul(rangeUsed,range.price).internal);
            consumption = decimal.sub(consumption,decimal.sub(rangeUsed).internal)
            startIndex = costPlan.indexOf(range)-1;
         }
         if(startIndex !== null){
           if(range.startRange > costPlan[costPlan.indexOf(range)-1].endRange){
              let rangeDifference = decimal.sub(range.startRange,costPlan[costPlan.indexOf(range)-1].endRange).internal;
              if(parseFloat(rangeDifference) > parseFloat(consumption)){
                 amount = decimal.add(amount,decimal.mul(consumption,costPlan.lostPrice).internal);
                 lostConsumption = decimal.add(lostConsumption,consumption);
                 lostAmount = decimal.add(lostAmount,decimal.mul(consumption,costPlan.lostPrice).internal);
                 break;
              }else{
                 consumption = decimal.sub(consumption,rangeDifference);
                 amount = decimal.add(amount,decimal.mul(rangeDifference,costPlan.lostPrice).internal);
                 lostConsumption = decimal.add(lostConsumption,rangeDifference);
                 lostAmount = decimal.add(lostAmount,decimal.mul(rangeDifference,costPlan.lostPrice).internal);
              }
           }
           let rangeCapacity = decimal.sub(range.endRange,range.startRange).internal;
           if(parseFloat(rangeCapacity) > parseFloat(consumption)){
              amount = decimal.add(amount,decimal.mul(consumption,range.price).internal);
              break;
           }else{
              consumption = decimal.sub(consumption,rangeCapacity);
              amount = decimal.add(amount,decimal.mul(rangeCapacity,range.price).internal);
           }
         }
      }
      return {newLadderBase:newLadderBase,amount:amount,lostConsumption:lostConsumption,lostAmount:lostAmount}
   },
   timeRangeCalculate(costPlan,dataList) {
         let costPlanList = util.costPlanTimeFormat(costPlan.rangeList);
         let timeRangeDailyObj = {
            date_accumulated:0,
            date_consumption:0,
            date_cost_amount:0,
            sharp_consumption:0,
            sharp_cost_amount:0,
            peak_consumption:0,
            peak_cost_amount:0,
            flat_consumption:0,
            flat_cost_amount:0,
            valley_consumption:0,
            valley_cost_amount:0,
            other_consumption:0,
            other_cost_amount:0,
         }
         for(let data of dataList){
            data.dataTime = data.endRange;
            data.startRange = util.timeRangeFormat( data.startRange);
            data.endRange = util.timeRangeFormat( data.endRange);
            let calculateWay = _.find(costPlanList,function (timeRange){
               return data.startRange >= timeRange.startRange && data.endRange <= timeRange.endRange;
            })
            let dataCostAmount = 0;
            if(calculateWay){
               dataCostAmount = decimal.mul(data.consumption,calculateWay.price).internal;
               timeRangeDailyObj[`${util.timeRangeObj[`${calculateWay.type}`]}_consumption`] = parseFloat(decimal.add(timeRangeDailyObj[`${util.timeRangeObj[`${calculateWay.type}`]}_consumption`],data.consumption).internal);
               timeRangeDailyObj[`${util.timeRangeObj[`${calculateWay.type}`]}_cost_amount`] = parseFloat(decimal.add(timeRangeDailyObj[`${util.timeRangeObj[`${calculateWay.type}`]}_cost_amount`],dataCostAmount).internal);
            }else{
               dataCostAmount = decimal.mul(data.consumption,costPlan.lostPrice).internal;
               timeRangeDailyObj[`other_consumption`] = parseFloat(decimal.add(timeRangeDailyObj[`other_consumption`],data.consumption).internal);
               timeRangeDailyObj[`other_cost_amount`] = parseFloat(decimal.add(timeRangeDailyObj[`other_cost_amount`],dataCostAmount).internal);
            }
            timeRangeDailyObj[`date_consumption`] =  parseFloat(decimal.add(timeRangeDailyObj[`date_consumption`],data.consumption).internal);
            timeRangeDailyObj[`date_cost_amount`] =  parseFloat(decimal.add(timeRangeDailyObj[`date_cost_amount`],dataCostAmount).internal);
            if(dataList.indexOf(data) === dataList.length - 1){
               timeRangeDailyObj["date_accumulated"] = data.accumulate;
               timeRangeDailyObj["last_data_time"] = data.dataTime;
            }
         }
         return timeRangeDailyObj;
      },
   costPlanTimeFormat(costPlanList){
      let formatCostPlanList = []
      for(let costPlan of costPlanList){
         costPlan.startRange = parseInt(costPlan.startRange);
         costPlan.endRange = parseInt(costPlan.endRange);
         if(costPlan.endRange < costPlan.startRange){
            formatCostPlanList.push({
               startRange:costPlan.startRange,
               endRange:parseInt(decimal.mul(24,3600).internal),
               price:costPlan.price,
               type:costPlan.type
            });
            formatCostPlanList.push({
               startRange:0,
               endRange:costPlan.startRange,
               price:costPlan.price,
               type:costPlan.type
            });
         }else{
            formatCostPlanList.push(costPlan);
         }
      }
      formatCostPlanList = _.sortBy(formatCostPlanList,function (data){ return data.startRange});
      return formatCostPlanList;
   },
   timeRangeFormat(timeRange){
      let hour = moment(timeRange).format("HH");
      let dateTimeStamp = decimal.mul(parseInt(hour),3600).internal;
      return parseInt(dateTimeStamp);
   }
}

module.exports = util;